#include "../mqserver/mq_virtualhost.hpp"
#include <gtest/gtest.h>

class VHTest : public testing::Test
{
public:
    void SetUp() override
    {
        LOG(DEBUG, "测试环境初始化中ing...\n");
        vp = std::make_shared<MQ::VirtualHost>("host1", "./data/host1/message/", "./data/host1/host1.db");

        std::unordered_map<std::string, std::string> empty_map = std::unordered_map<std::string, std::string>();
        vp->declareExchange("exchange1", MQ::ExchangeType::DIRECT, true, false, empty_map);
        vp->declareExchange("exchange2", MQ::ExchangeType::DIRECT, true, false, empty_map);
        vp->declareExchange("exchange3", MQ::ExchangeType::DIRECT, true, false, empty_map);

        vp->declareQueue("queue1", true, false, false, empty_map);
        vp->declareQueue("queue2", true, false, false, empty_map);
        vp->declareQueue("queue3", true, false, false, empty_map);

        vp->bind("exchange1", "queue1", "news.music.#");
        vp->bind("exchange1", "queue2", "news.music.#");
        vp->bind("exchange1", "queue3", "news.music.#");

        vp->bind("exchange2", "queue1", "news.music.#");
        vp->bind("exchange2", "queue2", "news.music.#");
        vp->bind("exchange2", "queue3", "news.music.#");

        vp->bind("exchange3", "queue1", "news.music.#");
        vp->bind("exchange3", "queue2", "news.music.#");
        vp->bind("exchange3", "queue3", "news.music.#");

        vp->basicPublish("queue1", nullptr, "Hello World-1");
        vp->basicPublish("queue1", nullptr, "Hello World-2");
        vp->basicPublish("queue1", nullptr, "Hello World-3");

        vp->basicPublish("queue2", nullptr, "Hello World-1");
        vp->basicPublish("queue2", nullptr, "Hello World-2");
        vp->basicPublish("queue2", nullptr, "Hello World-3");

        vp->basicPublish("queue3", nullptr, "Hello World-1");
        vp->basicPublish("queue3", nullptr, "Hello World-2");
        vp->basicPublish("queue3", nullptr, "Hello World-3");
    }

    void TearDown() override
    {
        LOG(DEBUG, "测试环境清理中ing...\n");
        vp->clear();
    }

public:
    MQ::VirtualHost::ptr vp;
};

// TEST_F(VHTest, queue_test)
// {
//     vp->basicPublish("queue2", nullptr, "Hello World-1");
//     vp->basicPublish("queue2", nullptr, "Hello World-2");
//     vp->basicPublish("queue2", nullptr, "Hello World-3");

//     MsgQueue::ptr mp1 = vp->selectQueue("queue1");
//     ASSERT_NE(mp1.get(), nullptr);
//     MsgQueue::ptr mp2 = vp->selectQueue("queue2");
//     ASSERT_NE(mp2.get(), nullptr);
//     MsgQueue::ptr mp3 = vp->selectQueue("queue3");
//     ASSERT_NE(mp3.get(), nullptr);

//     vp->basicPublish("queue1", nullptr, "Hello World-1");
//     vp->basicPublish("queue1", nullptr, "Hello World-2");
//     vp->basicPublish("queue1", nullptr, "Hello World-3");

//     MessagePtr msg1 = vp->basicConsume("queue1");
//     ASSERT_EQ(msg1->payload().body(), std::string("Hello World-1"));
//     MessagePtr msg2 = vp->basicConsume("queue1");
//     ASSERT_EQ(msg2->payload().body(), std::string("Hello World-2"));
//     MessagePtr msg3 = vp->basicConsume("queue1");
//     ASSERT_EQ(msg3->payload().body(), std::string("Hello World-3"));
// }

TEST_F(VHTest, init_test)
{
    ASSERT_EQ(vp->existsExchange("exchange1"), true);
    ASSERT_EQ(vp->existsExchange("exchange2"), true);
    ASSERT_EQ(vp->existsExchange("exchange3"), true);

    ASSERT_EQ(vp->existsQueue("queue1"), true);
    ASSERT_EQ(vp->existsQueue("queue2"), true);
    ASSERT_EQ(vp->existsQueue("queue3"), true);

    ASSERT_EQ(vp->existsBinding("exchange1", "queue1"), true);
    ASSERT_EQ(vp->existsBinding("exchange1", "queue2"), true);
    ASSERT_EQ(vp->existsBinding("exchange1", "queue3"), true);

    ASSERT_EQ(vp->existsBinding("exchange2", "queue1"), true);
    ASSERT_EQ(vp->existsBinding("exchange2", "queue2"), true);
    ASSERT_EQ(vp->existsBinding("exchange2", "queue3"), true);

    ASSERT_EQ(vp->existsBinding("exchange3", "queue1"), true);
    ASSERT_EQ(vp->existsBinding("exchange3", "queue2"), true);
    ASSERT_EQ(vp->existsBinding("exchange3", "queue3"), true);

    MQ::MessagePtr msg1 = vp->basicConsume("queue1");
    ASSERT_EQ(msg1->payload().body(), std::string("Hello World-1"));
    MQ::MessagePtr msg2 = vp->basicConsume("queue1");
    ASSERT_EQ(msg2->payload().body(), std::string("Hello World-2"));
    MQ::MessagePtr msg3 = vp->basicConsume("queue1");
    ASSERT_EQ(msg3->payload().body(), std::string("Hello World-3"));

    MQ::MessagePtr msg4 = vp->basicConsume("queue1");
    ASSERT_EQ(msg4.get(), nullptr);
}

TEST_F(VHTest, remove_exchange)
{
    vp->deleteExchange("exchange1");
    ASSERT_EQ(vp->existsBinding("exchange1", "queue1"), false);
    ASSERT_EQ(vp->existsBinding("exchange1", "queue2"), false);
    ASSERT_EQ(vp->existsBinding("exchange1", "queue3"), false);
}

TEST_F(VHTest, remove_queue)
{
    vp->deleteQueue("queue1");
    ASSERT_EQ(vp->existsBinding("exchange1", "queue1"), false);
    ASSERT_EQ(vp->existsBinding("exchange2", "queue1"), false);
    ASSERT_EQ(vp->existsBinding("exchange3", "queue1"), false);

    MQ::MessagePtr msg1 = vp->basicConsume("queue1");
    ASSERT_EQ(msg1.get(), nullptr);
}

TEST_F(VHTest, ack_message) 
{
    MQ::MessagePtr msg1 = vp->basicConsume("queue1");
    ASSERT_EQ(msg1->payload().body(), std::string("Hello World-1"));
    vp->basicAck(std::string("queue1"), msg1->payload().properties().id());

    MQ::MessagePtr msg2 = vp->basicConsume("queue1");
    ASSERT_EQ(msg2->payload().body(), std::string("Hello World-2"));
    vp->basicAck(std::string("queue1"), msg2->payload().properties().id());

    MQ::MessagePtr msg3 = vp->basicConsume("queue1");
    ASSERT_EQ(msg3->payload().body(), std::string("Hello World-3"));
    vp->basicAck(std::string("queue1"), msg3->payload().properties().id());
}

int main(int argc, char *argv[])
{
    testing::InitGoogleTest(&argc, argv);
    RUN_ALL_TESTS();
    return 0;
}